package Network;


/**
 * Class to create the appropriate message from a byte array, received from the 
 * Copyright (C) 2009 BBC Research, Sam Davies, <Sam.Davies@bbc.co.uk>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


 */
public class MessageParser {

    private char magic_0Hex = 0xe298;
    private char cellEntryHex = 0x1b1;
    private char cellExitHex = 0x12e;
    private char locationMessageHex = 0x26a;
    private char uplinkOnlyHex = 0x13d;
    private char buttonMessageHex = 0xbd;

    /**
     * An empty constructor is used as no variables or functions are accessable.
     */
    public MessageParser() {
    }
    /**
     * Parses the bytes and creates the correct Message depending upon the 
     * magic_1, identifying the message type
     * 
     * @param buf the 52 bytes of the message
     * @return A message for the correct type.
     */

    public Message parseMessage(byte[] buf) {
        //Parse the magic_1 byte to determine message
        char magic_1 = (char) ((0xff & buf[2]) << 8 | 0xff & buf[3]);
        Message message = null;

        if (magic_1 == locationMessageHex) {
            message = parseLocationMessage(buf);
        } else if (magic_1 == buttonMessageHex) {
            message = parseButtonMessage(buf);
        } else if (magic_1 == cellEntryHex) {
            message = parseCellEntryMessage(buf);
        } else if (magic_1 == cellExitHex) {
            message = parseCellExitMessage(buf);
        } else if (magic_1 == uplinkOnlyHex) {
            message = parseUplinkOnlyMessage(buf);
        }
        return message;
    }

    private CellEntryMessage parseCellEntryMessage(byte[] buf) {
        long tag_id_bottom = ((long) (buf[4]) << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]);
        long slot = ((long) (buf[8]) << 24 | (buf[9] & 0xff) << 16 | (buf[10] & 0xff) << 8 | (buf[11] & 0xff)) & 0xFFFFFFFFL;
        long cell = ((long) (0xff & buf[12]) << 24 | 0xff & buf[13] << 16 | 0xff & buf[14] << 8 | 0xff & buf[15]) & 0xFFFFFFFFL;
        CellEntryMessage cellEntryMessage = new CellEntryMessage(cellEntryHex, tag_id_bottom, slot, cell);
        return cellEntryMessage;

    }

    private CellExitMessage parseCellExitMessage(byte[] buf) {
        long tag_id_bottom = ((long) (buf[4]) << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]);
        long slot = ((long) (buf[8]) << 24 | (buf[9] & 0xff) << 16 | (buf[10] & 0xff) << 8 | (buf[11] & 0xff)) & 0xFFFFFFFFL;
        long cell = ((long) (0xff & buf[12]) << 24 | 0xff & buf[13] << 16 | 0xff & buf[14] << 8 | 0xff & buf[15]) & 0xFFFFFFFFL;
        CellExitMessage cellExitMessage = new CellExitMessage(cellExitHex, tag_id_bottom, slot, cell);
        return cellExitMessage;
    }

    private LocationMessage parseLocationMessage(byte[] buf) {
        long tag_id_top = 0;
        long tag_id_bottom = 0;
        long flags = 0;
        float x = 0;
        float y = 0;
        float z = 0;
        float gdop = 0;
        float error = 0;
        long slot = 0;
        long slot_interval = 0;
        long slot_delay = 0;
        long cell;


        tag_id_top = ((long) (0xff & buf[4]) << 24 | 0xff & buf[5] << 16 | 0xff & buf[6] << 8 | 0xff & buf[7]) & 0xFFFFFFFFL;

        //tag_id_bottom = ((long) (buf[4]) << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]);
        tag_id_bottom = ((long) (buf[8]) << 24 | buf[9] << 16 | buf[10] << 8 | buf[11]);

        flags = ((long) (buf[12]) << 24 | buf[13] << 16 | buf[14] << 8 | buf[15]);

        x = Float.intBitsToFloat(((buf[16]) << 24 | (buf[17] & 0xff) << 16 | (buf[18] & 0xff) << 8 | (buf[19] & 0xff)) & 0xFFFFFFFF);

        y = Float.intBitsToFloat(((buf[20]) << 24 | (buf[21] & 0xff) << 16 | (buf[22] & 0xff) << 8 | (buf[23] & 0xff)) & 0xFFFFFFFF);
        z = Float.intBitsToFloat(((buf[24]) << 24 | (buf[25] & 0xff) << 16 | (buf[26] & 0xff) << 8 | (buf[27] & 0xff)) & 0xFFFFFFFF);


        gdop = Float.intBitsToFloat(((buf[28]) << 24 | (buf[29] & 0xff) << 16 | (buf[30] & 0xff) << 8 | (buf[31] & 0xff)) & 0xFFFFFFFF);
        error = Float.intBitsToFloat(((buf[32]) << 24 | (buf[33] & 0xff) << 16 | (buf[34] & 0xff) << 8 | (buf[35] & 0xff)) & 0xFFFFFFFF);

        slot = ((long) (buf[36]) << 24 | (buf[37] & 0xff) << 16 | (buf[38] & 0xff) << 8 | (buf[39] & 0xff)) & 0xFFFFFFFFL;
        slot_interval = ((long) (buf[40]) << 24 | (buf[41] & 0xff) << 16 | (buf[42] & 0xff) << 8 | (buf[43] & 0xff)) & 0xFFFFFFFFL;
        slot_delay = ((long) (0xff & buf[44]) << 24 | 0xff & buf[45] << 16 | 0xff & buf[46] << 8 | 0xff & buf[47]) & 0xFFFFFFFFL;

        cell = ((long) (0xff & buf[48]) << 24 | 0xff & buf[49] << 16 | 0xff & buf[50] << 8 | 0xff & buf[51]) & 0xFFFFFFFFL;

        LocationMessage locationMessage = new LocationMessage(locationMessageHex, tag_id_top, tag_id_bottom, flags, x, y, z, gdop, error, slot, slot_interval, slot_delay, cell);
System.out.println("Tag: "+tag_id_bottom+" coords: "+x+" "+y+" "+z+ "a");
        return locationMessage;

    }

    private UplinkOnlyMessage parseUplinkOnlyMessage(byte[] buf) {
        long tag_id_bottom = ((long) (buf[8]) << 24 | buf[9] << 16 | buf[10] << 8 | buf[11]);
        long slot = ((long) (buf[12]) << 24 | (buf[13] & 0xff) << 16 | (buf[14] & 0xff) << 8 | (buf[15] & 0xff)) & 0xFFFFFFFFL;
        long cell = ((long) (0xff & buf[16]) << 24 | 0xff & buf[17] << 16 | 0xff & buf[18] << 8 | 0xff & buf[19]) & 0xFFFFFFFFL;
        char trembleSwitch = (char) ((buf[20] & 0xff) << 8 | (buf[21] & 0xff));
        char rssi = (char) ((buf[18] & 0xff) << 8 | (buf[19] & 0xff));

        UplinkOnlyMessage uplinkOnlyMessage = new UplinkOnlyMessage(uplinkOnlyHex, tag_id_bottom, slot, cell, trembleSwitch, rssi);
        return uplinkOnlyMessage;

    }

    private ButtonMessage parseButtonMessage(byte[] buf) {
        //long tag_id_top = ((long) (0xff & buf[4]) << 24 | 0xff & buf[5] << 16 | 0xff & buf[6] << 8 | 0xff & buf[7]) & 0xFFFFFFFFL;

        long tag_id_bottom = ((long) (buf[4]) << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]);
        long slot = ((long) (buf[8]) << 24 | (buf[9] & 0xff) << 16 | (buf[10] & 0xff) << 8 | (buf[11] & 0xff)) & 0xFFFFFFFFL;
        char orange = (char) ((buf[12] & 0xff) << 8 | (buf[13] & 0xff));
        char blue = (char) ((buf[12] & 0xff) << 8 | (buf[13] & 0xff));

        ButtonMessage buttonMessage = new ButtonMessage(buttonMessageHex, tag_id_bottom, slot, orange, blue);
        return buttonMessage;
    }
}
